package cn.wubo.multi.thread.demo02;

import java.util.concurrent.Semaphore;
import java.util.stream.IntStream;

/**
 * 通过Semaphore信号量加锁
 * 1、Semaphore信号量作为一种流控手段，可以对特定资源的允许同时访问的操作数量进行控制，例如池化技术(连接池)中的并发数，有界阻塞容器的容量等。
 * 2、Semaphore中包含初始化时固定个数的许可，在进行操作的时候，需要先acquire获取到许可，才可以继续执行任务，如果获取失败，则进入阻塞；处理完成之后需要release释放许可。
 * 3、acquire与release之间的关系：在实现中不包含真正的许可对象，并且Semaphore也不会将许可与线程关联起来，因此在一个线程中获得的许可可以在另一个线程中释放。可以将acquire操作视为是消费一个许可，而release操作是创建一个许可，Semaphore并不受限于它在创建时的初始许可数量。也就是说acquire与release并没有强制的一对一关系，release一次就相当于新增一个许可，许可的数量可能会由于没有与acquire操作一对一而导致超出初始化时设置的许可个数。
 */
public class Demo0203 {
    //定义总张数
    public static int tickets = 10;
    private static Semaphore semaphore = new Semaphore(1);

    public static void main(String[] args) {
        IntStream.range(0, 15).forEach(i -> new Thread(Demo0203::ticket).start());
    }

    public static void ticket() {
        try {
            Thread.sleep((int) (Math.random() * 100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //判断车票是否大于0
        try {
            //加锁
            semaphore.acquire();
            if (Demo0203.tickets > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出第" + Demo0203.tickets + "张车票");
                Demo0203.tickets--;
                //模仿出票
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println(Thread.currentThread().getName() + "无票");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            //释放锁
            semaphore.release();
        }
    }
}